package com.navi.mould1.reportUtils;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.*;

import static org.apache.commons.lang3.StringUtils.isBlank;

/**
 *  对列表、对象列表进行排序工具类，可支持多个排序条件，和不同排序方式。
 *  例子 :
 *      LKListUtils.sort(yieldDataBeanList, new String[] { "maxLotTime", "baseId", "gradeGpId" }, new boolean[] { true, true, true, true});
 */
public final class LKingSortUtil {

    /**
     * 对列表进行排序
     * @param <T> 泛型
     * @param list 列表
     * @param fieldNames 字段名称数组
     * @param isAscs 是否升序数组
     */
    public static <T> void sort(List<T> list, final String[] fieldNames, final boolean[] isAscs) {
        Collections.sort(list, new Comparator<T>() {

            @Override
            public int compare(T x, T y) {
                int result = 0;
                for (int i = 0; i < fieldNames.length; i++) {
                    result = LKingSortUtil.compare(x, y, fieldNames[i], isAscs[i]);
                    if (result != 0) {
                        break;
                    }
                }
                return result;
            }

        });
    }





    /**
     * 比较两个对象的大小
     * @param <T> 泛型
     * @param x 对象
     * @param y 对象
     * @param fieldName 字段名
     * @param isAsc 是否升序
     * @return 比较结果。大于0：x比y大；等于0：x与y相等；小于0：x比y小。
     */
    public static <T> int compare(T x, T y, String fieldName, boolean isAsc) {
        return compare(fieldName, isAsc, LKingSortUtil.getFieldValue(x, fieldName), LKingSortUtil.getFieldValue(y, fieldName));
    }


    /**
     * 比较两个对象的大小
     * @param fieldName 字段名
     * @param isAsc 是否升序
     * @param valueX 对象X的值
     * @param valueY 对象Y的值
     * @return 比较结果。大于0：x比y大；等于0：x与y相等；小于0：x比y小。
     */
    private static int compare(String fieldName, boolean isAsc, Object valueX, Object valueY) {
        if (valueX == null) {
            if (valueY == null) {
                return 0;
            }
            return compareResult(isAsc, false);
        } else {
            if (valueY == null) {
                return compareResult(isAsc, true);
            }
        }

        if ((valueX instanceof Number) && (valueY instanceof Number)) {
            double xValue = ((Number) valueX).doubleValue();
            double yValue = ((Number) valueY).doubleValue();
            if (xValue > yValue) {
                return compareResult(isAsc, true);
            } else if (xValue == yValue) {
                return 0;
            } else {
                return compareResult(isAsc, false);
            }
        }

        if ((valueX instanceof Date) && (valueY instanceof Date)) {
            long xValue = ((Date) valueX).getTime();
            long yValue = ((Date) valueY).getTime();
            if (xValue > yValue) {
                return compareResult(isAsc, false);
            } else if (xValue == yValue) {
                return 0;
            } else {
                return compareResult(isAsc, true);
            }
        }

        if ((valueX instanceof java.sql.Date) && (valueY instanceof java.sql.Date)) {
            long xValue = ((java.sql.Date) valueX).getTime();
            long yValue = ((java.sql.Date) valueY).getTime();
            if (xValue > yValue) {
                return compareResult(isAsc, false);
            } else if (xValue == yValue) {
                return 0;
            } else {
                return compareResult(isAsc, true);
            }
        }

        String xValue = toString(valueX, "");
        String yValue = toString(valueY, "");

        return isAsc ? xValue.compareTo(yValue) : yValue.compareTo(xValue);
    }

    /**
     * 转换为String类型对象
     * @param obj 对象
     * @param defaultValue 默认值.
     * @return String类型对象
     */
    public static String toString(final Object obj, final String defaultValue) {
        if (obj != null) {
            return LKingSortUtil.toString(obj.toString(), defaultValue);
        }
        return defaultValue;
    }

    /**
     * 转换成String类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * </pre>
     *
     * @param cs 字符数组。
     * @param defaultValue 默认值
     * @return String类型值
     */
    public static String toString(final CharSequence cs, final String defaultValue) {
        if (isBlank(cs)) {
            return defaultValue;
        }
        return trimToEmpty(cs);
    }

    /**
     * 去除空格。并将认定java中的空(null)和javascript(undefined)中的空都为空。
     *
     * <pre>
     * assertEquals(LKStringUtils.trimToEmpty(null), "");
     * assertEquals(LKStringUtils.trimToEmpty(""), "");
     * assertEquals(LKStringUtils.trimToEmpty(" "), "");
     * assertEquals(LKStringUtils.trimToEmpty("null"), "");
     * assertEquals(LKStringUtils.trimToEmpty(" null"), "");
     * assertEquals(LKStringUtils.trimToEmpty("null "), "");
     * assertEquals(LKStringUtils.trimToEmpty("undefined"), "");
     * assertEquals(LKStringUtils.trimToEmpty(" undefined"), "");
     * assertEquals(LKStringUtils.trimToEmpty("undefined "), "");
     *
     * assertEquals(LKStringUtils.trimToEmpty("other"), "other");
     * assertEquals(LKStringUtils.trimToEmpty(" other"), "other");
     * assertEquals(LKStringUtils.trimToEmpty("other "), "other");
     * </pre>
     *
     * @param cs 字符串
     * @return 去除空格后的字符串
     */
    public static String trimToEmpty(final CharSequence cs) {
        if ((cs == null) || "".equals(cs)) {
            return "";
        }
        final String str = cs.toString().trim();
        if ("null".equalsIgnoreCase(str) || "undefined".equals(str)) {
            return "";
        }
        return str;
    }


    /**
     * 比较结果
     * @param isAsc 是否正序
     * @param isLarger 是否大于
     */
    private static int compareResult(boolean isAsc, boolean isLarger) {
        return isAsc ? (isLarger ? 1 : -1) : (isLarger ? -1 : 1);
    }

    /**
     * 获取字段值
     * @param obj 对象
     * @param fieldName 字段名
     * @return 字段值
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        if (obj != null) {
            try {
                return accessableField(obj.getClass(), fieldName).get(obj);
            } catch (Exception e) {
                // ignore this
            }
        }
        return null;
    }


    /**
     * 获取字段
     * @param clazz 类型
     * @param fieldName 字段名
     * @return 字段
     */
    public static Field accessableField(Class<?> clazz, String fieldName) {
        final Field field = getAllFields(clazz, fieldName)[0];
        field.setAccessible(true);
        return field;
    }


    /**
     * 获取字段数组
     * @param clazz 类型
     * @param fieldNames 字段名称。希望获取的字段名称，将会按照指定顺序返回。如果不传该值，则将按照默认顺序返回。
     * @return 字段数组
     */
    public static Field[] getAllFields(Class<?> clazz, String... fieldNames) {
        final Field[] fileds = FieldUtils.getAllFields(clazz);
        if (ArrayUtils.isEmpty(fieldNames)) {
            // 返回默认顺序
            return fileds;
        }
        final Field[] orderedFields = new Field[fieldNames.length];
        out: for (int i = 0; i < fieldNames.length; i++) {
            final String fieldName = fieldNames[i];
            for (final Field field : fileds) {
                if (fieldName.equals(field.getName())) {
                    orderedFields[i] = field;
                    continue out;
                }
            }
        }
        return orderedFields;
    }

}
